package com.woniuxy.service.impl;


import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.woniuxy.commons.exception.AccountException;
import com.woniuxy.commons.exception.LateException;
import com.woniuxy.commons.exception.LoginPhoneException;
import com.woniuxy.commons.utile.BeanCopyUtil;
import com.woniuxy.commons.utile.CommonsUtil;
import com.woniuxy.controller.dto.AccountDto;
import com.woniuxy.controller.dto.GetAllStudentDto;
import com.woniuxy.controller.form.AccountForm;
import com.woniuxy.controller.form.RepairpeopleForm;
import com.woniuxy.controller.form.SetAccountForm;
import com.woniuxy.dao.*;
import com.woniuxy.dao.model.*;
import com.woniuxy.service.AccountService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import javax.mail.MessagingException;
import javax.security.auth.login.LoginException;

import java.util.List;
import java.util.Random;
import java.util.concurrent.TimeUnit;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author Keep it simple
 * @since 2022-06-28
 */
@Service
public class AccountServiceImpl extends ServiceImpl<AccountDao, Account> implements AccountService, UserDetailsService {


    @Resource
    private AccountDao accountDao;

    @Resource
    private StringRedisTemplate srt;

    @Resource
    private AccountService accountService;

    @Resource
    private UriInfoDao uriInfoDao;

    @Resource
    private RoleInfoDao roleInfoDao;

    @Resource
    private AccountRoleDao accountRoleDao;

    @Resource
    private UserProjectAreaDao userProjectAreaDao;

    @Resource
    private RepairRepairerUnitDao repairRepairerUnitDao;



    @Override
    /**
     * 添加维修人员
     * @param RepairpeopleForm
     * @return
     */
    public String addrepairpeople(RepairpeopleForm repairpeopleForm) {
        if (repairpeopleForm.getAccountName()==null)throw new LateException(1102,"姓名不能为空");
        if (repairpeopleForm.getAccountEmail()==null)throw new LateException(1102,"邮箱不能为空");
        if (repairpeopleForm.getAccountPhone()==null)throw new LateException(1102,"电话不能为空");
        if (repairpeopleForm.getCompany()==null)throw new LateException(1102,"公司不能为空");
        if (repairpeopleForm.getArea()==null)throw new LateException(1102,"区域不能为空");
        Account account = BeanCopyUtil.copyOne(repairpeopleForm, Account.class);
        account.setState(1);
        account.setAccountState(1);
        Random random = new Random();
        Integer nextInt = random.nextInt(100);
        long l = System.currentTimeMillis();
        account.setAccount((nextInt+"")+(l+""));
        int insert = accountDao.insert(account);
        QueryWrapper<Account> accountQueryWrapper = new QueryWrapper<>();
        accountQueryWrapper.eq("account_name",repairpeopleForm.getAccountName());
        Account account1 = accountDao.selectOne(accountQueryWrapper);
        Integer id = account1.getId();
        UserProjectArea userProjectArea = new UserProjectArea();
        userProjectArea.setZid(id);//维修人员id
        userProjectArea.setAreacode(repairpeopleForm.getArea());
        userProjectArea.setState(1);
        userProjectAreaDao.insert(userProjectArea);
        RepairRepairerUnit repairRepairerUnit = new RepairRepairerUnit();
        repairRepairerUnit.setAccountId(id);
        repairRepairerUnit.setUnitId(repairpeopleForm.getCompany());
        System.out.println(repairRepairerUnit);
        repairRepairerUnitDao.insert(repairRepairerUnit);
        AccountRole accountRole = new AccountRole();
        accountRole.setAccountId(id);
        accountRole.setRoleId(1L);
        accountRole.setRoleIdentify("MaintenanceWorker");
        accountRoleDao.insert(accountRole);
        return account.getAccount();
    }

    /**
     * 学生注册
     * @param accountForm
     * @return
     */
    @Override
    public Account register(AccountForm accountForm) throws MessagingException {
        Account account = BeanCopyUtil.copyOne(accountForm, Account.class);
        //生成账号
        Random random = new Random();
        Integer nextInt = random.nextInt(100);
        long l = System.currentTimeMillis();
        account.setAccount((nextInt+"")+(l+""));

        //发激活码
        String activeCode = CommonsUtil.getActiveCode(64);
        CommonsUtil.sendMail(accountForm.getAccountEmail(),
                    "用户激活",
                "<a href='http://127.0.0.1:8888/account/activation?activeCode="+activeCode+"'>激活账户</a>");

        account.setAccountActivation(activeCode);
        //注册
        int insert = accountDao.insert(account);

        Account account1 = accountDao.selectOne(new QueryWrapper<Account>().eq("account", account.getAccount()));
        //将账号与角色关联
        RoleInfo roleInfo = roleInfoDao.selectOne(new QueryWrapper<RoleInfo>().eq("role_id", 2L));
        AccountRole accountRole = new AccountRole();
        accountRole.setRoleIdentify(roleInfo.getRoleIdentify());
        accountRole.setRoleId(2L);
        accountRole.setAccountId(account1.getId());
        accountRoleDao.insert(accountRole);

        return account1;
    }

    /**
     * 账号激活
     * @param activeCode
     * @return
     */
    @Override
    public void activation(String activeCode) {
        accountDao.activation(activeCode);
    }


    /**
     * 获取验证码（可用于短信验证登录   注册时判断手机号是否属于该用户）
     * @param phone
     * @return
     */
    @Override
    public String sendCode(String phone) {
        //从redis中获取存的验证码，如果取到了说明验证码已经发送
        String phoneCode = srt.opsForValue().get("login:phone:code:" + phone);
        if (phoneCode != null) throw new LoginPhoneException(1002,"验证码已发送，60秒内无法再次发送验证码");

        //生成验证码
        StringBuffer code = new StringBuffer();
        Random random = new Random();
        for (int i = 0; i <4 ; i++) {
            code.append(random.nextInt(10));
        }
        //将验证码存到redis中并设置过期时间
        srt.opsForValue().setIfAbsent("login:phone:code:" + phone,code.toString(),60, TimeUnit.SECONDS);
        System.out.println("向"+phone+"发送验证码"+code);
        return null;
    }

    /**
     * 修改信息
     * @param accountForm
     * @return
     */
    @Override
    public Account setAccount(SetAccountForm accountForm) {
        AccountDto AccountDto = (AccountDto) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        Integer num = accountDao.setAccount(accountForm,AccountDto.getAccount());
        if (num==0) throw new LoginPhoneException(1007,"信息修改失败");
        AccountDto accountDto = (AccountDto)SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        Account account = accountDao.selectOne(new QueryWrapper<Account>().eq("account", accountDto.getAccount()));
        return account;
    }

    /**
     * 修改密码
     * @param code password
     * @return
     */
    @Override
    public AccountDto setPassword(String code, String password) {
        if (code == null || code.equals("")) throw new LoginPhoneException(1010,"验证码不能为空");
        if (password == null || password.equals("")) throw new LoginPhoneException(1010,"密码不能为空");
        AccountDto AccountDto = (AccountDto) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        String codes = srt.opsForValue().get("login:phone:code:" + AccountDto.getAccountPhone());
        if (code == null || !(code.equals(codes))) throw  new LoginPhoneException(1008,"验证码有误或已失效");
        UpdateWrapper<Account> wrapper = new UpdateWrapper<>();
        wrapper.set("password",password);
        wrapper.eq("account",AccountDto.getAccount());
        boolean update = accountService.update(wrapper);
        if (update){
            AccountDto.setPassword(password);
            return AccountDto;
        }throw new LoginPhoneException(1008,"密码修改失败");
    }

    /**
     * 修改电话
     * @param code Phone
     * @param phone
     * @return
     */
    @Override
    public AccountDto setPhone(String code, String phone) {
        if (code == null || code.equals("")) throw new LoginPhoneException(1010,"验证码不能为空");
        if (phone == null || phone.equals("")) throw new LoginPhoneException(1010,"电话不能为空");
        AccountDto AccountDto = (AccountDto) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        String codes = srt.opsForValue().get("login:phone:code:" + phone);
        System.out.println(codes);
        if (code == null || !(code.equals(codes))) throw  new LoginPhoneException(1008,"验证码有误或已失效");
        UpdateWrapper<Account> wrapper = new UpdateWrapper<>();
        wrapper.set("account_phone",phone);
        wrapper.eq("account",AccountDto.getAccount());
        boolean update = accountService.update(wrapper);
        if (update){
            AccountDto.setAccountPhone(phone);
            return AccountDto;
        }throw new LoginPhoneException(1008,"电话修改失败");

    }

    /**
     * 修改邮箱
     * @param activeCode
     * @param email
     * @return
     */
    @Override
    public AccountDto MailboxVerification2(String activeCode, String email) {
        AccountDto accountDto = (AccountDto)SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        String s = srt.opsForValue().get("code:" + accountDto.getAccount());
        if (s==null)throw new com.woniuxy.commons.exception.AccountException(1012,"邮箱验证码码有误或失效");
        UpdateWrapper<Account> wrapper = new UpdateWrapper<>();
        wrapper.set("account_email",email);
        wrapper.eq("account",accountDto.getAccount());
        boolean update = accountService.update(wrapper);
        if (update){
            accountDto.setAccountEmail(email);
            return accountDto;
        }throw new AccountException(1012,"邮箱修改失败");
    }

    /**
     * 修改用户名
     * @param accountName
     * @return accountDto
     */
    @Override
    public AccountDto setAccountName(String accountName) {
        AccountDto accountDto = (AccountDto)SecurityContextHolder.getContext().getAuthentication().getPrincipal();
        UpdateWrapper<Account> wrapper = new UpdateWrapper<>();
        wrapper.set("account_name",accountName);
        wrapper.eq("account",accountDto.getAccount());
        boolean update = accountService.update(wrapper);
        if (update){
            accountDto.setAccountName(accountName);
            return accountDto;
        }throw new AccountException(1013,"用户名修改失败");
    }

    @Override
    public Page<GetAllStudentDto> getAllStudent(Integer pageNum,Integer pageSize) {
        System.out.println(pageNum+":"+pageSize);
        Page<Account> state = accountDao.selectPage(new Page<Account>(pageNum, pageSize), new QueryWrapper<Account>().eq("state", 2));
        Page<GetAllStudentDto> allStudentDtoPage = BeanCopyUtil.copyPages(state, GetAllStudentDto.class);
        return allStudentDtoPage;
    }

    /**
     * 账号密码登录
     * @param accounts
     * @return accountDto
     * @throws UsernameNotFoundException
     */
    @Override
    public UserDetails loadUserByUsername(String accounts) throws UsernameNotFoundException {
        Account account = accountDao.selectOne(new QueryWrapper<Account>().eq("account", accounts));

        //获取redis中的"account:"+accounts 存在说明账号锁定
        String s = srt.opsForValue().get("account:"+accounts);

        if (s==null) {
            //判断账号是否是激活状态
            if (account.getAccountState() == 0) throw new LoginPhoneException(1004, "账号未激活或者被禁用");
            if (account == null) throw new LoginPhoneException(1001, "账号不存在");
            System.out.println(account);
            AccountDto accountDto = new AccountDto();
            accountDto.setId(account.getId());
            accountDto.setAccount(account.getAccount());
            accountDto.setAccountEmail(account.getAccountEmail());
            accountDto.setAccountName(account.getAccountName());
            accountDto.setId(account.getId());
            accountDto.setState(account.getState());
            //添加头像地址
            accountDto.setAccountTouXin(account.getAccountTouxin());
            //给密码加密去比较
            accountDto.setPassword(new BCryptPasswordEncoder().encode(account.getPassword()));
            accountDto.setAccountPhone(account.getAccountPhone());

            //存一个账号在redis中
            srt.opsForValue().setIfAbsent("account"+ account.getAccount(),"0",1,TimeUnit.DAYS);
//            srt.opsForHash().put("account","account"+accountDto.getAccount(),0);
            //查该账号的uri资源
            List<String> uris = uriInfoDao.loadUriValue(account.getId());
            if(uris != null && uris.size()>0)accountDto.setRoles(uris);
            return accountDto;
        }throw new LoginPhoneException(1005,"该账号被锁定");
    }
}
